1 /*!
2     \file    gd32f4xx_fmc.c
3     \brief   FMC driver
4 
5     \version 2016-08-15, V1.0.0, firmware for GD32F4xx
6     \version 2018-12-12, V2.0.0, firmware for GD32F4xx
7     \version 2020-09-30, V2.1.0, firmware for GD32F4xx
8     \version 2022-03-09, V3.0.0, firmware for GD32F4xx
9 */
10 
11 /*
12     Copyright (c) 2022, 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 
39 #include "gd32f4xx_fmc.h"
40 
41 /*!
42     \brief    set the wait state counter value
43     \param[in]  wscnt: wait state counter value
44                 only one parameter can be selected which is shown as below:
45       \arg        WS_WSCNT_0: FMC 0 wait
46       \arg        WS_WSCNT_1: FMC 1 wait
47       \arg        WS_WSCNT_2: FMC 2 wait
48       \arg        WS_WSCNT_3: FMC 3 wait
49       \arg        WS_WSCNT_4: FMC 4 wait
50       \arg        WS_WSCNT_5: FMC 5 wait
51       \arg        WS_WSCNT_6: FMC 6 wait
52       \arg        WS_WSCNT_7: FMC 7 wait
53       \arg        WS_WSCNT_8: FMC 8 wait
54       \arg        WS_WSCNT_9: FMC 9 wait
55       \arg        WS_WSCNT_10: FMC 10 wait
56       \arg        WS_WSCNT_11: FMC 11 wait
57       \arg        WS_WSCNT_12: FMC 12 wait
58       \arg        WS_WSCNT_13: FMC 13 wait
59       \arg        WS_WSCNT_14: FMC 14 wait
60       \arg        WS_WSCNT_15: FMC 15 wait
61     \param[out] none
62     \retval     none
63 */
fmc_wscnt_set(uint32_t wscnt)64 void fmc_wscnt_set(uint32_t wscnt)
65 {
66     uint32_t reg;
67 
68     reg = FMC_WS;
69     /* set the wait state counter value */
70     reg &= ~FMC_WC_WSCNT;
71     FMC_WS = (reg | wscnt);
72 }
73 
74 /*!
75     \brief    unlock the main FMC operation
76     \param[in]  none
77     \param[out] none
78     \retval     none
79 */
fmc_unlock(void)80 void fmc_unlock(void)
81 {
82     if((RESET != (FMC_CTL & FMC_CTL_LK))) {
83         /* write the FMC key */
84         FMC_KEY = UNLOCK_KEY0;
85         FMC_KEY = UNLOCK_KEY1;
86     }
87 }
88 
89 /*!
90     \brief    lock the main FMC operation
91     \param[in]  none
92     \param[out] none
93     \retval     none
94 */
fmc_lock(void)95 void fmc_lock(void)
96 {
97     /* set the LK bit*/
98     FMC_CTL |= FMC_CTL_LK;
99 }
100 
101 #if defined (GD32F425) || defined (GD32F427) || defined (GD32F470)
102 
103 /*!
104     \brief      FMC erase page
105     \param[in]  page_addr: the page address to be erased.
106     \param[out] none
107     \retval     state of FMC
108       \arg        FMC_READY: the operation has been completed
109       \arg        FMC_BUSY: the operation is in progress
110       \arg        FMC_RDDERR: read D-bus protection error
111       \arg        FMC_PGSERR: program sequence error
112       \arg        FMC_PGMERR: program size not match error
113       \arg        FMC_WPERR: erase/program protection error
114       \arg        FMC_OPERR: operation error
115       \arg        FMC_TOERR: timeout error
116 */
fmc_page_erase(uint32_t page_addr)117 fmc_state_enum fmc_page_erase(uint32_t page_addr)
118 {
119     fmc_state_enum fmc_state = FMC_READY;
120 
121     /* wait for the FMC ready */
122     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
123 
124     if(FMC_READY == fmc_state) {
125         /* unlock  */
126         FMC_PEKEY = UNLOCK_PE_KEY;
127 
128         /* start page erase */
129         FMC_PECFG = FMC_PE_EN | page_addr;
130         FMC_CTL &= ~FMC_CTL_SN;
131         FMC_CTL |= FMC_CTL_SER;
132         FMC_CTL |= FMC_CTL_START;
133 
134         /* wait for the FMC ready */
135         fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
136 
137         FMC_PECFG &= ~FMC_PE_EN;
138         FMC_CTL &= ~FMC_CTL_SER;
139     }
140 
141     /* return the FMC state */
142     return fmc_state;
143 }
144 
145 #endif
146 
147 /*!
148     \brief    erase sector
149     \param[in]  fmc_sector: select the sector to erase
150                 only one parameter can be selected which is shown as below:
151       \arg        CTL_SECTOR_NUMBER_0: sector 0
152       \arg        CTL_SECTOR_NUMBER_1: sector 1
153       \arg        CTL_SECTOR_NUMBER_2: sector 2
154       \arg        CTL_SECTOR_NUMBER_3: sector 3
155       \arg        CTL_SECTOR_NUMBER_4: sector 4
156       \arg        CTL_SECTOR_NUMBER_5: sector 5
157       \arg        CTL_SECTOR_NUMBER_6: sector 6
158       \arg        CTL_SECTOR_NUMBER_7: sector 7
159       \arg        CTL_SECTOR_NUMBER_8: sector 8
160       \arg        CTL_SECTOR_NUMBER_9: sector 9
161       \arg        CTL_SECTOR_NUMBER_10: sector 10
162       \arg        CTL_SECTOR_NUMBER_11: sector 11
163       \arg        CTL_SECTOR_NUMBER_12: sector 12
164       \arg        CTL_SECTOR_NUMBER_13: sector 13
165       \arg        CTL_SECTOR_NUMBER_14: sector 14
166       \arg        CTL_SECTOR_NUMBER_15: sector 15
167       \arg        CTL_SECTOR_NUMBER_16: sector 16
168       \arg        CTL_SECTOR_NUMBER_17: sector 17
169       \arg        CTL_SECTOR_NUMBER_18: sector 18
170       \arg        CTL_SECTOR_NUMBER_19: sector 19
171       \arg        CTL_SECTOR_NUMBER_20: sector 20
172       \arg        CTL_SECTOR_NUMBER_21: sector 21
173       \arg        CTL_SECTOR_NUMBER_22: sector 22
174       \arg        CTL_SECTOR_NUMBER_23: sector 23
175       \arg        CTL_SECTOR_NUMBER_24: sector 24
176       \arg        CTL_SECTOR_NUMBER_25: sector 25
177       \arg        CTL_SECTOR_NUMBER_26: sector 26
178       \arg        CTL_SECTOR_NUMBER_27: sector 27
179     \param[out] none
180     \retval     state of FMC
181       \arg        FMC_READY: the operation has been completed
182       \arg        FMC_BUSY: the operation is in progress
183       \arg        FMC_RDDERR: read D-bus protection error
184       \arg        FMC_PGSERR: program sequence error
185       \arg        FMC_PGMERR: program size not match error
186       \arg        FMC_WPERR: erase/program protection error
187       \arg        FMC_OPERR: operation error
188       \arg        FMC_TOERR: timeout error
189 */
fmc_sector_erase(uint32_t fmc_sector)190 fmc_state_enum fmc_sector_erase(uint32_t fmc_sector)
191 {
192     fmc_state_enum fmc_state = FMC_READY;
193     /* wait for the FMC ready */
194     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
195 
196     if(FMC_READY == fmc_state) {
197         /* start sector erase */
198         FMC_CTL &= ~FMC_CTL_SN;
199         FMC_CTL |= (FMC_CTL_SER | fmc_sector);
200         FMC_CTL |= FMC_CTL_START;
201 
202         /* wait for the FMC ready */
203         fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
204 
205         /* reset the SER bit */
206         FMC_CTL &= (~FMC_CTL_SER);
207         FMC_CTL &= ~FMC_CTL_SN;
208     }
209 
210     /* return the FMC state */
211     return fmc_state;
212 }
213 
214 /*!
215     \brief    erase whole chip
216     \param[in]  none
217     \param[out] none
218     \retval     state of FMC
219       \arg        FMC_READY: the operation has been completed
220       \arg        FMC_BUSY: the operation is in progress
221       \arg        FMC_RDDERR: read D-bus protection error
222       \arg        FMC_PGSERR: program sequence error
223       \arg        FMC_PGMERR: program size not match error
224       \arg        FMC_WPERR: erase/program protection error
225       \arg        FMC_OPERR: operation error
226       \arg        FMC_TOERR: timeout error
227 */
fmc_mass_erase(void)228 fmc_state_enum fmc_mass_erase(void)
229 {
230     fmc_state_enum fmc_state = FMC_READY;
231     /* wait for the FMC ready */
232     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
233 
234     if(FMC_READY == fmc_state) {
235         /* start whole chip erase */
236         FMC_CTL |= (FMC_CTL_MER0 | FMC_CTL_MER1);
237         FMC_CTL |= FMC_CTL_START;
238 
239         /* wait for the FMC ready */
240         fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
241 
242         /* reset the MER bits */
243         FMC_CTL &= ~(FMC_CTL_MER0 | FMC_CTL_MER1);
244     }
245 
246     /* return the fmc state */
247     return fmc_state;
248 }
249 
250 /*!
251     \brief    erase all FMC sectors in bank0
252     \param[in]  none
253     \param[out] none
254     \retval     state of FMC
255       \arg        FMC_READY: the operation has been completed
256       \arg        FMC_BUSY: the operation is in progress
257       \arg        FMC_RDDERR: read D-bus protection error
258       \arg        FMC_PGSERR: program sequence error
259       \arg        FMC_PGMERR: program size not match error
260       \arg        FMC_WPERR: erase/program protection error
261       \arg        FMC_OPERR: operation error
262       \arg        FMC_TOERR: timeout error
263 */
fmc_bank0_erase(void)264 fmc_state_enum fmc_bank0_erase(void)
265 {
266     fmc_state_enum fmc_state = FMC_READY;
267     /* wait for the FMC ready */
268     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
269 
270     if(FMC_READY == fmc_state) {
271         /* start FMC bank0 erase */
272         FMC_CTL |= FMC_CTL_MER0;
273         FMC_CTL |= FMC_CTL_START;
274 
275         /* wait for the FMC ready */
276         fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
277 
278         /* reset the MER0 bit */
279         FMC_CTL &= (~FMC_CTL_MER0);
280     }
281 
282     /* return the fmc state */
283     return fmc_state;
284 }
285 
286 /*!
287     \brief    erase all FMC sectors in bank1
288     \param[in]  none
289     \param[out] none
290     \retval     state of FMC
291       \arg        FMC_READY: the operation has been completed
292       \arg        FMC_BUSY: the operation is in progress
293       \arg        FMC_RDDERR: read D-bus protection error
294       \arg        FMC_PGSERR: program sequence error
295       \arg        FMC_PGMERR: program size not match error
296       \arg        FMC_WPERR: erase/program protection error
297       \arg        FMC_OPERR: operation error
298       \arg        FMC_TOERR: timeout error
299 */
fmc_bank1_erase(void)300 fmc_state_enum fmc_bank1_erase(void)
301 {
302     fmc_state_enum fmc_state = FMC_READY;
303     /* wait for the FMC ready */
304     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
305 
306     if(FMC_READY == fmc_state) {
307         /* start FMC bank1 erase */
308         FMC_CTL |= FMC_CTL_MER1;
309         FMC_CTL |= FMC_CTL_START;
310 
311         /* wait for the FMC ready */
312         fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
313 
314         /* reset the MER1 bit */
315         FMC_CTL &= (~FMC_CTL_MER1);
316     }
317 
318     /* return the fmc state */
319     return fmc_state;
320 }
321 
322 /*!
323     \brief    program a word at the corresponding address
324     \param[in]  address: address to program
325     \param[in]  data: word to program(0x00000000 - 0xFFFFFFFF)
326     \param[out] none
327     \retval     state of FMC
328       \arg        FMC_READY: the operation has been completed
329       \arg        FMC_BUSY: the operation is in progress
330       \arg        FMC_RDDERR: read D-bus protection error
331       \arg        FMC_PGSERR: program sequence error
332       \arg        FMC_PGMERR: program size not match error
333       \arg        FMC_WPERR: erase/program protection error
334       \arg        FMC_OPERR: operation error
335       \arg        FMC_TOERR: timeout error
336 */
fmc_word_program(uint32_t address,uint32_t data)337 fmc_state_enum fmc_word_program(uint32_t address, uint32_t data)
338 {
339     fmc_state_enum fmc_state = FMC_READY;
340     /* wait for the FMC ready */
341     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
342 
343     if(FMC_READY == fmc_state) {
344         /* set the PG bit to start program */
345         FMC_CTL &= ~FMC_CTL_PSZ;
346         FMC_CTL |= CTL_PSZ_WORD;
347         FMC_CTL |= FMC_CTL_PG;
348 
349         REG32(address) = data;
350 
351         /* wait for the FMC ready */
352         fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
353 
354         /* reset the PG bit */
355         FMC_CTL &= ~FMC_CTL_PG;
356     }
357 
358     /* return the FMC state */
359     return fmc_state;
360 }
361 
362 /*!
363     \brief    program a half word at the corresponding address
364     \param[in]  address: address to program
365     \param[in]  data: halfword to program(0x0000 - 0xFFFF)
366     \param[out] none
367     \retval     state of FMC
368       \arg        FMC_READY: the operation has been completed
369       \arg        FMC_BUSY: the operation is in progress
370       \arg        FMC_RDDERR: read D-bus protection error
371       \arg        FMC_PGSERR: program sequence error
372       \arg        FMC_PGMERR: program size not match error
373       \arg        FMC_WPERR: erase/program protection error
374       \arg        FMC_OPERR: operation error
375       \arg        FMC_TOERR: timeout error
376 */
fmc_halfword_program(uint32_t address,uint16_t data)377 fmc_state_enum fmc_halfword_program(uint32_t address, uint16_t data)
378 {
379     fmc_state_enum fmc_state = FMC_READY;
380     /* wait for the FMC ready */
381     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
382 
383     if(FMC_READY == fmc_state) {
384         /* set the PG bit to start program */
385         FMC_CTL &= ~FMC_CTL_PSZ;
386         FMC_CTL |= CTL_PSZ_HALF_WORD;
387         FMC_CTL |= FMC_CTL_PG;
388 
389         REG16(address) = data;
390 
391         /* wait for the FMC ready */
392         fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
393 
394         /* reset the PG bit */
395         FMC_CTL &= ~FMC_CTL_PG;
396     }
397 
398     /* return the FMC state */
399     return fmc_state;
400 }
401 
402 /*!
403     \brief    program a byte at the corresponding address
404     \param[in]  address: address to program
405     \param[in]  data: byte to program(0x00 - 0xFF)
406     \param[out] none
407     \retval     state of FMC
408       \arg        FMC_READY: the operation has been completed
409       \arg        FMC_BUSY: the operation is in progress
410       \arg        FMC_RDDERR: read D-bus protection error
411       \arg        FMC_PGSERR: program sequence error
412       \arg        FMC_PGMERR: program size not match error
413       \arg        FMC_WPERR: erase/program protection error
414       \arg        FMC_OPERR: operation error
415       \arg        FMC_TOERR: timeout error
416 */
fmc_byte_program(uint32_t address,uint8_t data)417 fmc_state_enum fmc_byte_program(uint32_t address, uint8_t data)
418 {
419     fmc_state_enum fmc_state = FMC_READY;
420     /* wait for the FMC ready */
421     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
422 
423     if(FMC_READY == fmc_state) {
424         /* set the PG bit to start program */
425         FMC_CTL &= ~FMC_CTL_PSZ;
426         FMC_CTL |= CTL_PSZ_BYTE;
427         FMC_CTL |= FMC_CTL_PG;
428 
429         REG8(address) = data;
430 
431         /* wait for the FMC ready */
432         fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
433 
434         /* reset the PG bit */
435         FMC_CTL &= ~FMC_CTL_PG;
436     }
437 
438     /* return the FMC state */
439     return fmc_state;
440 }
441 
442 /*!
443     \brief    unlock the option byte operation
444     \param[in]  none
445     \param[out] none
446     \retval     none
447 */
ob_unlock(void)448 void ob_unlock(void)
449 {
450     if(RESET != (FMC_OBCTL0 & FMC_OBCTL0_OB_LK)) {
451         /* write the FMC key */
452         FMC_OBKEY = OB_UNLOCK_KEY0;
453         FMC_OBKEY = OB_UNLOCK_KEY1;
454     }
455 }
456 
457 /*!
458     \brief    lock the option byte operation
459     \param[in]  none
460     \param[out] none
461     \retval     none
462 */
ob_lock(void)463 void ob_lock(void)
464 {
465     /* reset the OB_LK bit */
466     FMC_OBCTL0 |= FMC_OBCTL0_OB_LK;
467 }
468 
469 /*!
470     \brief    send option byte change command
471     \param[in]  none
472     \param[out] none
473     \retval     none
474 */
ob_start(void)475 void ob_start(void)
476 {
477     /* set the OB_START bit in OBCTL0 register */
478     FMC_OBCTL0 |= FMC_OBCTL0_OB_START;
479 }
480 
481 /*!
482     \brief    erase option byte
483     \param[in]  none
484     \param[out] none
485     \retval     none
486 */
ob_erase(void)487 void ob_erase(void)
488 {
489     uint32_t reg, reg1;
490     fmc_state_enum fmc_state = FMC_READY;
491     /* wait for the FMC ready */
492     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
493     reg = FMC_OBCTL0;
494     reg1 = FMC_OBCTL1;
495 
496     if(FMC_READY == fmc_state) {
497 
498         /* reset the OB_FWDGT, OB_DEEPSLEEP and OB_STDBY, set according to ob_fwdgt ,ob_deepsleep and ob_stdby */
499         reg |= (FMC_OBCTL0_NWDG_HW | FMC_OBCTL0_NRST_DPSLP | FMC_OBCTL0_NRST_STDBY);
500         /* reset the BOR level */
501         reg |= FMC_OBCTL0_BOR_TH;
502         /* reset option byte boot bank value */
503         reg &= ~FMC_OBCTL0_BB;
504         /* reset option byte dbs value */
505         reg &= ~FMC_OBCTL0_DBS;
506 
507         /* reset drp and wp value */
508         reg |= FMC_OBCTL0_WP0;
509         reg &= (~FMC_OBCTL0_DRP);
510         FMC_OBCTL0 = reg;
511 
512         reg1 |= FMC_OBCTL1_WP1;
513         FMC_OBCTL1 = reg1;
514 
515         FMC_OBCTL0 = reg;
516     }
517 }
518 
519 /*!
520     \brief    enable write protection
521     \param[in]  ob_wp: specify sector to be write protected
522                 one or more parameters can be selected which are shown as below:
523       \arg        OB_WP_x(x=0..22):sector x(x = 0,1,2...22)
524       \arg        OB_WP_23_27: sector23~27
525       \arg        OB_WP_ALL: all sector
526     \param[out] none
527     \retval     SUCCESS or ERROR
528 */
ob_write_protection_enable(uint32_t ob_wp)529 ErrStatus ob_write_protection_enable(uint32_t ob_wp)
530 {
531     uint32_t reg0 = FMC_OBCTL0;
532     uint32_t reg1 = FMC_OBCTL1;
533     fmc_state_enum fmc_state = FMC_READY;
534     if(RESET != (FMC_OBCTL0 & FMC_OBCTL0_DRP)) {
535         return ERROR;
536     }
537     /* wait for the FMC ready */
538     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
539 
540     if(FMC_READY == fmc_state) {
541         reg0 &= (~((uint32_t)ob_wp << 16U));
542         reg1 &= (~(ob_wp & 0xFFFF0000U));
543         FMC_OBCTL0 = reg0;
544         FMC_OBCTL1 = reg1;
545 
546         return SUCCESS;
547     } else {
548         return ERROR;
549     }
550 }
551 
552 /*!
553     \brief    disable write protection
554     \param[in]  ob_wp: specify sector to be write protected
555                 one or more parameters can be selected which are shown as below:
556       \arg        OB_WP_x(x=0..22):sector x(x = 0,1,2...22)
557       \arg        OB_WP_23_27: sector23~27
558       \arg        OB_WP_ALL: all sector
559     \param[out] none
560     \retval     SUCCESS or ERROR
561 */
ob_write_protection_disable(uint32_t ob_wp)562 ErrStatus ob_write_protection_disable(uint32_t ob_wp)
563 {
564     uint32_t reg0 = FMC_OBCTL0;
565     uint32_t reg1 = FMC_OBCTL1;
566     fmc_state_enum fmc_state = FMC_READY;
567     if(RESET != (FMC_OBCTL0 & FMC_OBCTL0_DRP)) {
568         return ERROR;
569     }
570     /* wait for the FMC ready */
571     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
572 
573     if(FMC_READY == fmc_state) {
574         reg0 |= ((uint32_t)ob_wp << 16U);
575         reg1 |= (ob_wp & 0xFFFF0000U);
576         FMC_OBCTL0 = reg0;
577         FMC_OBCTL1 = reg1;
578 
579         return SUCCESS;
580     } else {
581         return ERROR;
582     }
583 }
584 
585 /*!
586     \brief    enable erase/program protection and D-bus read protection
587     \param[in]  ob_drp: enable the WPx bits used as erase/program protection and D-bus read protection of each sector
588                 one or more parameters can be selected which are shown as below:
589       \arg        OB_DRP_x(x=0..22): sector x(x = 0,1,2...22)
590       \arg        OB_DRP_23_27: sector23~27
591       \arg        OB_DRP_ALL: all sector
592     \param[out] none
593     \retval     none
594 */
ob_drp_enable(uint32_t ob_drp)595 void ob_drp_enable(uint32_t ob_drp)
596 {
597     uint32_t reg0 = FMC_OBCTL0;
598     uint32_t reg1 = FMC_OBCTL1;
599     fmc_state_enum fmc_state = FMC_READY;
600     uint32_t drp_state = FMC_OBCTL0 & FMC_OBCTL0_DRP;
601     uint32_t wp0_state = FMC_OBCTL0 & FMC_OBCTL0_WP0;
602     uint32_t wp1_state = FMC_OBCTL1 & FMC_OBCTL1_WP1;
603 
604     /* wait for the FMC ready */
605     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
606 
607     if(FMC_READY == fmc_state) {
608         if(RESET == drp_state) {
609             reg0 &= ~FMC_OBCTL0_WP0;
610             reg1 &= ~FMC_OBCTL1_WP1;
611         }
612         reg0 |= ((uint32_t)ob_drp << 16U);
613         reg0 |= FMC_OBCTL0_DRP;
614         reg1 |= ((uint32_t)ob_drp & 0xFFFF0000U);
615 
616         FMC_OBCTL0 = reg0;
617         FMC_OBCTL1 = reg1;
618     }
619 }
620 
621 /*!
622     \brief    disable erase/program protection and D-bus read protection
623     \param[in]  ob_drp: disable the WPx bits used as erase/program protection and D-bus read protection of each sector
624                 one or more parameters can be selected which are shown as below:
625       \arg        OB_DRP_x(x=0..22): sector x(x = 0,1,2...22)
626       \arg        OB_DRP_23_27: sector23~27
627       \arg        OB_DRP_ALL: all sector
628     \param[out] none
629     \retval     none
630 */
ob_drp_disable(void)631 void ob_drp_disable(void)
632 {
633     uint32_t reg0 = FMC_OBCTL0;
634     uint32_t reg1 = FMC_OBCTL1;
635     fmc_state_enum fmc_state = FMC_READY;
636     /* wait for the FMC ready */
637     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
638 
639     if(FMC_READY == fmc_state) {
640         if(((uint8_t)(reg0 >> 8U)) == (uint8_t)FMC_NSPC) {
641             /* security protection should be set as low level protection before disable D-BUS read protection */
642             reg0 &= ~FMC_OBCTL0_SPC;
643             reg0 |= ((uint32_t)FMC_LSPC << 8U);
644             FMC_OBCTL0 = reg0;
645             /* set the OB_START bit in OBCTL0 register */
646             FMC_OBCTL0 |= FMC_OBCTL0_OB_START;
647         }
648 
649         /* it is necessary to disable the security protection at the same time when D-BUS read protection is disabled */
650         reg0 &= ~FMC_OBCTL0_SPC;
651         reg0 |= ((uint32_t)FMC_NSPC << 8U);
652         reg0 |= FMC_OBCTL0_WP0;
653         reg0 &= (~FMC_OBCTL0_DRP);
654         FMC_OBCTL0 = reg0;
655 
656         reg1 |= FMC_OBCTL1_WP1;
657         FMC_OBCTL1 = reg1;
658 
659     }
660 }
661 
662 /*!
663     \brief    configure security protection level
664     \param[in]  ob_spc: specify security protection level
665                 only one parameter can be selected which is shown as below:
666       \arg        FMC_NSPC: no security protection
667       \arg        FMC_LSPC: low security protection
668       \arg        FMC_HSPC: high security protection
669     \param[out] none
670     \retval     none
671 */
ob_security_protection_config(uint8_t ob_spc)672 void ob_security_protection_config(uint8_t ob_spc)
673 {
674     fmc_state_enum fmc_state = FMC_READY;
675     /* wait for the FMC ready */
676     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
677 
678     if(FMC_READY == fmc_state) {
679         uint32_t reg;
680 
681         reg = FMC_OBCTL0;
682         /* reset the OBCTL0_SPC, set according to ob_spc */
683         reg &= ~FMC_OBCTL0_SPC;
684         reg |= ((uint32_t)ob_spc << 8U);
685         FMC_OBCTL0 = reg;
686     }
687 }
688 
689 /*!
690     \brief    program the FMC user option byte
691     \param[in]  ob_fwdgt: option byte watchdog value
692                 only one parameter can be selected which is shown as below:
693       \arg        OB_FWDGT_SW: software free watchdog
694       \arg        OB_FWDGT_HW: hardware free watchdog
695     \param[in]  ob_deepsleep: option byte deepsleep reset value
696                 only one parameter can be selected which is shown as below:
697       \arg        OB_DEEPSLEEP_NRST: no reset when entering deepsleep mode
698       \arg        OB_DEEPSLEEP_RST: generate a reset instead of entering deepsleep mode
699     \param[in]  ob_stdby:option byte standby reset value
700                 only one parameter can be selected which is shown as below:
701       \arg        OB_STDBY_NRST: no reset when entering standby mode
702       \arg        OB_STDBY_RST: generate a reset instead of entering standby mode
703     \param[out] none
704     \retval     none
705 */
ob_user_write(uint32_t ob_fwdgt,uint32_t ob_deepsleep,uint32_t ob_stdby)706 void ob_user_write(uint32_t ob_fwdgt, uint32_t ob_deepsleep, uint32_t ob_stdby)
707 {
708     fmc_state_enum fmc_state = FMC_READY;
709 
710     /* wait for the FMC ready */
711     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
712 
713     if(FMC_READY == fmc_state) {
714         uint32_t reg;
715 
716         reg = FMC_OBCTL0;
717         /* reset the OB_FWDGT, OB_DEEPSLEEP and OB_STDBY, set according to ob_fwdgt ,ob_deepsleep and ob_stdby */
718         reg &= ~(FMC_OBCTL0_NWDG_HW | FMC_OBCTL0_NRST_DPSLP | FMC_OBCTL0_NRST_STDBY);
719         FMC_OBCTL0 = (reg | ob_fwdgt | ob_deepsleep | ob_stdby);
720     }
721 }
722 
723 /*!
724     \brief    program the option byte BOR threshold value
725     \param[in]  ob_bor_th: user option byte
726                 only one parameter can be selected which is shown as below:
727       \arg        OB_BOR_TH_VALUE3: BOR threshold value 3
728       \arg        OB_BOR_TH_VALUE2: BOR threshold value 2
729       \arg        OB_BOR_TH_VALUE1: BOR threshold value 1
730       \arg        OB_BOR_TH_OFF: no BOR function
731     \param[out] none
732     \retval     none
733 */
ob_user_bor_threshold(uint32_t ob_bor_th)734 void ob_user_bor_threshold(uint32_t ob_bor_th)
735 {
736     uint32_t reg;
737 
738     reg = FMC_OBCTL0;
739     /* set the BOR level */
740     reg &= ~FMC_OBCTL0_BOR_TH;
741     FMC_OBCTL0 = (reg | ob_bor_th);
742 }
743 
744 /*!
745     \brief    configure the option byte boot bank value
746     \param[in]  boot_mode: specifies the option byte boot bank value
747                 only one parameter can be selected which is shown as below:
748       \arg        OB_BB_DISABLE: boot from bank0
749       \arg        OB_BB_ENABLE: boot from bank1 or bank0 if bank1 is void
750     \param[out] none
751     \retval     none
752 */
ob_boot_mode_config(uint32_t boot_mode)753 void ob_boot_mode_config(uint32_t boot_mode)
754 {
755     uint32_t reg;
756 
757     reg = FMC_OBCTL0;
758     /* set option byte boot bank value */
759     reg &= ~FMC_OBCTL0_BB;
760     FMC_OBCTL0 = (reg | boot_mode);
761 }
762 
763 /*!
764     \brief    get the FMC user option byte
765     \param[in]  none
766     \param[out] none
767     \retval     the FMC user option byte values: ob_fwdgt(Bit0), ob_deepsleep(Bit1), ob_stdby(Bit2)
768 */
ob_user_get(void)769 uint8_t ob_user_get(void)
770 {
771     return (uint8_t)((uint8_t)(FMC_OBCTL0 >> 5U) & 0x07U);
772 }
773 
774 /*!
775     \brief    get the FMC option byte write protection
776     \param[in]  none
777     \param[out] none
778     \retval     the FMC write protection option byte value
779 */
ob_write_protection0_get(void)780 uint16_t ob_write_protection0_get(void)
781 {
782     /* return the FMC write protection option byte value */
783     return (uint16_t)(((uint16_t)(FMC_OBCTL0 >> 16U)) & 0x0FFFU);
784 }
785 
786 /*!
787     \brief    get the FMC option byte write protection
788     \param[in]  none
789     \param[out] none
790     \retval     the FMC write protection option byte value
791 */
ob_write_protection1_get(void)792 uint16_t ob_write_protection1_get(void)
793 {
794     /* return the the FMC write protection option byte value */
795     return (uint16_t)(((uint16_t)(FMC_OBCTL1 >> 16U)) & 0x0FFFU);
796 }
797 
798 /*!
799     \brief    get the FMC D-bus read protection protection
800     \param[in]  none
801     \param[out] none
802     \retval     the FMC erase/program protection and D-bus read protection option bytes value
803 */
ob_drp0_get(void)804 uint16_t ob_drp0_get(void)
805 {
806     /* return the FMC erase/program protection and D-bus read protection option bytes value */
807     if(FMC_OBCTL0 & FMC_OBCTL0_DRP) {
808         return (uint16_t)(((uint16_t)(FMC_OBCTL0 >> 16U)) & 0x0FFFU);
809     } else {
810         return 0xF000U;
811     }
812 }
813 
814 /*!
815     \brief    get the FMC D-bus read protection protection
816     \param[in]  none
817     \param[out] none
818     \retval     the FMC erase/program protection and D-bus read protection option bytes value
819 */
ob_drp1_get(void)820 uint16_t ob_drp1_get(void)
821 {
822     /* return the FMC erase/program protection and D-bus read protection option bytes value */
823     if(FMC_OBCTL0 & FMC_OBCTL0_DRP) {
824         return (uint16_t)(((uint16_t)(FMC_OBCTL1 >> 16U)) & 0x0FFFU);
825     } else {
826         return 0xF000U;
827     }
828 }
829 
830 /*!
831     \brief    get the FMC option byte security protection
832     \param[in]  none
833     \param[out] none
834     \retval     FlagStatus: SET or RESET
835 */
ob_spc_get(void)836 FlagStatus ob_spc_get(void)
837 {
838     FlagStatus spc_state = RESET;
839 
840     if(((uint8_t)(FMC_OBCTL0 >> 8U)) != FMC_NSPC) {
841         spc_state = SET;
842     } else {
843         spc_state = RESET;
844     }
845     return spc_state;
846 }
847 
848 /*!
849     \brief    get the FMC option byte BOR threshold value
850     \param[in]  none
851     \param[out] none
852     \retval     the FMC BOR threshold value:OB_BOR_TH_OFF,OB_BOR_TH_VALUE1,OB_BOR_TH_VALUE2,OB_BOR_TH_VALUE3
853 */
ob_user_bor_threshold_get(void)854 uint8_t ob_user_bor_threshold_get(void)
855 {
856     /* return the FMC BOR threshold value */
857     return (uint8_t)((uint8_t)FMC_OBCTL0 & 0x0CU);
858 }
859 
860 /*!
861     \brief    get flag set or reset
862     \param[in]  fmc_flag: check FMC flag
863                 only one parameter can be selected which is shown as below:
864       \arg        FMC_FLAG_BUSY: FMC busy flag bit
865       \arg        FMC_FLAG_RDDERR: FMC read D-bus protection error flag bit
866       \arg        FMC_FLAG_PGSERR: FMC program sequence error flag bit
867       \arg        FMC_FLAG_PGMERR: FMC program size not match error flag bit
868       \arg        FMC_FLAG_WPERR: FMC Erase/Program protection error flag bit
869       \arg        FMC_FLAG_OPERR: FMC operation error flag bit
870       \arg        FMC_FLAG_END: FMC end of operation flag bit
871     \param[out] none
872     \retval     FlagStatus: SET or RESET
873 */
fmc_flag_get(uint32_t fmc_flag)874 FlagStatus fmc_flag_get(uint32_t fmc_flag)
875 {
876     if(FMC_STAT & fmc_flag) {
877         return SET;
878     }
879     /* return the state of corresponding FMC flag */
880     return RESET;
881 }
882 
883 /*!
884     \brief    clear the FMC pending flag
885     \param[in]  FMC_flag: clear FMC flag
886                 only one parameter can be selected which is shown as below:
887       \arg        FMC_FLAG_RDDERR: FMC read D-bus protection error flag bit
888       \arg        FMC_FLAG_PGSERR: FMC program sequence error flag bit
889       \arg        FMC_FLAG_PGMERR: FMC program size not match error flag bit
890       \arg        FMC_FLAG_WPERR: FMC erase/program protection error flag bit
891       \arg        FMC_FLAG_OPERR: FMC operation error flag bit
892       \arg        FMC_FLAG_END: FMC end of operation flag bit
893     \param[out] none
894     \retval     none
895 */
fmc_flag_clear(uint32_t fmc_flag)896 void fmc_flag_clear(uint32_t fmc_flag)
897 {
898     /* clear the flags */
899     FMC_STAT = fmc_flag;
900 }
901 
902 /*!
903     \brief    enable FMC interrupt
904     \param[in]  fmc_int: the FMC interrupt source
905                 only one parameter can be selected which is shown as below:
906       \arg        FMC_INT_END: enable FMC end of program interrupt
907       \arg        FMC_INT_ERR: enable FMC error interrupt
908     \param[out] none
909     \retval     none
910 */
fmc_interrupt_enable(uint32_t fmc_int)911 void fmc_interrupt_enable(uint32_t fmc_int)
912 {
913     FMC_CTL |= fmc_int;
914 }
915 
916 /*!
917     \brief    disable FMC interrupt
918     \param[in]  fmc_int: the FMC interrupt source
919                 only one parameter can be selected which is shown as below:
920       \arg        FMC_INT_END: disable FMC end of program interrupt
921       \arg        FMC_INT_ERR: disable FMC error interrupt
922     \param[out] none
923     \retval     none
924 */
fmc_interrupt_disable(uint32_t fmc_int)925 void fmc_interrupt_disable(uint32_t fmc_int)
926 {
927     FMC_CTL &= ~(uint32_t)fmc_int;
928 }
929 
930 /*!
931     \brief    get FMC interrupt flag set or reset
932     \param[in]  fmc_int_flag: FMC interrupt flag
933                 only one parameter can be selected which is shown as below:
934       \arg        FMC_INT_FLAG_RDDERR: FMC read D-bus protection error interrupt flag
935       \arg        FMC_INT_FLAG_PGSERR: FMC program sequence error interrupt flag
936       \arg        FMC_INT_FLAG_PGMERR: FMC program size not match error interrupt flag
937       \arg        FMC_INT_FLAG_WPERR: FMC Erase/Program protection error interrupt flag
938       \arg        FMC_INT_FLAG_OPERR: FMC operation error interrupt flag
939       \arg        FMC_INT_FLAG_END: FMC end of operation interrupt flag
940     \param[out] none
941     \retval     FlagStatus: SET or RESET
942 */
fmc_interrupt_flag_get(uint32_t fmc_int_flag)943 FlagStatus fmc_interrupt_flag_get(uint32_t fmc_int_flag)
944 {
945     if(FMC_FLAG_END == fmc_int_flag) {
946         /* end of operation interrupt flag */
947         if(FMC_CTL & FMC_CTL_ENDIE) {
948             if(FMC_STAT & fmc_int_flag) {
949                 return SET;
950             }
951         }
952     } else {
953         /* error interrupt flags */
954         if(FMC_CTL & FMC_CTL_ERRIE) {
955             if(FMC_STAT & fmc_int_flag) {
956                 return SET;
957             }
958         }
959     }
960 
961     return RESET;
962 }
963 
964 /*!
965     \brief    clear the FMC interrupt flag
966     \param[in]  fmc_int_flag: FMC interrupt flag
967                 only one parameter can be selected which is shown as below:
968       \arg        FMC_INT_FLAG_RDDERR: FMC read D-bus protection error interrupt flag
969       \arg        FMC_INT_FLAG_PGSERR: FMC program sequence error interrupt flag
970       \arg        FMC_INT_FLAG_PGMERR: FMC program size not match error interrupt flag
971       \arg        FMC_INT_FLAG_WPERR: FMC Erase/Program protection error interrupt flag
972       \arg        FMC_INT_FLAG_OPERR: FMC operation error interrupt flag
973       \arg        FMC_INT_FLAG_END: FMC end of operation interrupt flag
974     \param[out] none
975     \retval     none
976 */
fmc_interrupt_flag_clear(uint32_t fmc_int_flag)977 void fmc_interrupt_flag_clear(uint32_t fmc_int_flag)
978 {
979     /* clear the interrupt flag */
980     FMC_STAT = fmc_int_flag;
981 }
982 
983 /*!
984     \brief    get the FMC state
985     \param[in]  none
986     \param[out] none
987     \retval     state of FMC
988       \arg        FMC_READY: the operation has been completed
989       \arg        FMC_BUSY: the operation is in progress
990       \arg        FMC_RDDERR: read D-bus protection error
991       \arg        FMC_PGSERR: program sequence error
992       \arg        FMC_PGMERR: program size not match error
993       \arg        FMC_WPERR: erase/program protection error
994       \arg        FMC_OPERR: operation error
995 */
fmc_state_get(void)996 fmc_state_enum fmc_state_get(void)
997 {
998     fmc_state_enum fmc_state = FMC_READY;
999     uint32_t temp_val = FMC_STAT;
1000 
1001     if(RESET != (temp_val & FMC_FLAG_BUSY)) {
1002         fmc_state = FMC_BUSY;
1003     } else if(RESET != (temp_val & FMC_FLAG_RDDERR)) {
1004         fmc_state = FMC_RDDERR;
1005     } else if(RESET != (temp_val & FMC_FLAG_PGSERR)) {
1006         fmc_state = FMC_PGSERR;
1007     } else if(RESET != (temp_val & FMC_FLAG_PGMERR)) {
1008         fmc_state = FMC_PGMERR;
1009     } else if(RESET != (temp_val & FMC_FLAG_WPERR)) {
1010         fmc_state = FMC_WPERR;
1011     } else if(RESET != (temp_val & FMC_FLAG_OPERR)) {
1012         fmc_state = FMC_OPERR;
1013     } else {
1014         fmc_state = FMC_READY;
1015     }
1016 
1017     /* return the FMC state */
1018     return fmc_state;
1019 }
1020 
1021 /*!
1022     \brief    check whether FMC is ready or not
1023     \param[in]  none
1024     \param[out] none
1025     \retval     state of FMC
1026       \arg        FMC_READY: the operation has been completed
1027       \arg        FMC_BUSY: the operation is in progress
1028       \arg        FMC_RDDERR: read D-bus protection error
1029       \arg        FMC_PGSERR: program sequence error
1030       \arg        FMC_PGMERR: program size not match error
1031       \arg        FMC_WPERR: erase/program protection error
1032       \arg        FMC_OPERR: operation error
1033       \arg        FMC_TOERR: timeout error
1034 */
fmc_ready_wait(uint32_t timeout)1035 fmc_state_enum fmc_ready_wait(uint32_t timeout)
1036 {
1037     fmc_state_enum fmc_state = FMC_BUSY;
1038 
1039     /* wait for FMC ready */
1040     do {
1041         /* get FMC state */
1042         fmc_state = fmc_state_get();
1043         timeout--;
1044     } while((FMC_BUSY == fmc_state) && (0U != timeout));
1045 
1046     if(0U == timeout) {
1047         fmc_state = FMC_TOERR;
1048     }
1049 
1050     /* return the FMC state */
1051     return fmc_state;
1052 }
1053